// Copyright 2011, Vanya Davidenko.
// Кодировка файла: UTF-8. 
package info.iu9.red;



abstract class StringIterator implements StringPosition {
  abstract int next();

  // Доступ к итерируемой строке.
  String string() {
    return string_;
  }

  // Индекс текущего символа (без проверки границ).
  int index() {
    return index_;
  }
  protected void set_index(final int index) {
    index_ = index;
  }

  protected int begin() {
    return begin_;
  }
  protected int end() {
    return end_;
  }

  protected int current_char_length() {
    return current_char_length_;
  }
  protected void set_current_char_length(final int current_char_lenth) {
    current_char_length_ = current_char_lenth;
  }

  // Получение предыдущего символа или EOL в случае выхода за границу строки(!),
  // но не среза. Граничные условия проверяются не через isBegin,
  // а isStringBegin, так как вне зависимости от выбранного интервала,
  // якорям нужно проверять предыдущий символ строки и возвращать EOF,
  // на границе среза было бы ошибкой при возврате Dfa.
  public int getPrev() {
    if ( isStringBegin() ) { return EOL; }
    return string_.codePointAt(prevIndex());
  }

  // Хак для ReverseEndingAnchorState.
  public int getPrevPrev() {
    if ( isStringBegin() ) { return EOL; }

    final int original_index = index_;
    index_ = prevIndex();

    final int result = getPrev();
    index_ = original_index;
    return result;
  }
  // Получение текущего символа или EOL в случае выхода за границу строки.
  public int getCurrent() {
    if ( isStringEnd() ) {
      return EOL;
    }

    if ( current_char_length_ == 1 ) {
      return string_.charAt(index());
    } else {
      assert current_char_length_ == 2;
      return Character.toCodePoint(string_.charAt(index()),
                                   string_.charAt(index() + 1));
    }
  }
  // Получение следующего символа или EOL в случае выхода за границу строки.
  public int getNext() {
    if ( nextIsStringEnd() ) { return EOL; }
    return string_.codePointAt(nextIndex());
  }

  protected void reset(final String string, final int begin, final int end) {
    if ( !checkBounds(string, begin_, end_) ) {
      throw new IllegalArgumentException();
    }

    string_ = string;
    begin_ = begin;
    end_ = end;

    concreteReset();
  }

  // Паттерн "Шаблонный метод".

  public abstract boolean isStringBegin();
  public abstract boolean isStringEnd();

  protected abstract int prevIndex();
  protected abstract int nextIndex();
  protected abstract boolean nextIsStringEnd();

  protected abstract void concreteReset();

  protected abstract boolean checkBounds(final String string,
                                         final int begin, final int end);

  private String string_;

  private int begin_;
  private int end_;

  private int index_;
  private int current_char_length_;
}
